#ifndef XMLPARSER_H
#define XMLPARSER_H

//==============================================================================
//
//           XMLParser - the parser class in the gpxtools library
//
//               Copyright (C) 2018  Dick van Oudheusden
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free
// Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
//==============================================================================

#include <iostream>
#include <map>

#include "expat.h"

namespace gpxtools
{
  ///
  /// @class XMLParserHandler
  ///
  /// @brief The xml parser handler class.
  ///
  class XMLParserHandler
  {
  public:
    XMLParserHandler() {}
    virtual ~XMLParserHandler() {}

    typedef std::map<std::string, std::string> Attributes;

    virtual void startElement(const std::string &path, const std::string &name, const Attributes &attributes) = 0;
    virtual void endElement(const std::string &path, const std::string &name) = 0;
    virtual void text(const std::string &path, const std::string &text) = 0;
  };

  ///
  /// @class XMLParser
  ///
  /// @brief The xml parser class.
  ///
  
  class XMLParser
  {
  public:

    ///
    /// Constructor
    ///
    ///
    XMLParser(XMLParserHandler *handler);

    ///
    /// Deconstructor
    ///
    virtual ~XMLParser();

    // Properties
    ///
    /// Get the last error text
    ///
    /// @return the last error text
    ///
    const std::string &errorText() const { return _errorText; }

    ///
    /// Get the last error line number
    ///
    /// @return the last error line number
    ///
    int errorLineNumber() const { return _errorLineNumber; }

    ///
    /// Get the last error column number
    ///
    /// @return the last error column number
    ///
    int errorColumnNumber() const { return _errorColumnNumber; }

  public:

    // Parsing methods

    ///
    /// Parse data
    ///
    /// @param  data    the data to be parsed
    /// @param  length  the length of the data
    /// @param  isFinal is this the last data ?
    ///
    /// @return success
    ///
    bool parse(const char *data, int length, bool isFinal);

    ///
    /// Parse text
    ///
    /// @param  text    the zero terminated text to be parsed
    /// @param  isFinal is this the last data ?
    ///
    /// @return success
    ///
    bool parse(const char *text, bool isFinal);

    ///
    /// Parse string
    ///
    /// @param  data    the data to be parsed
    /// @param  isFinal is this the last data ?
    ///
    /// @return success
    ///
    bool parse(const std::string &data, bool isFinal);

    ///
    /// Parse an input stream
    ///
    /// @param  stream        the stream to be parsed
    ///
    /// @return success
    ///
    bool parse(std::istream &stream);

    ///
    /// Trim a string
    ///
    /// @param  text          the string to be trimmed
    ///
    static void trim(std::string &text);

  private:

    // Start using expat
    void startExpat();

    // Stop using expat
    void stopExpat();

    // Statics for expat
    static void startElementHandler         (void *userData, const XML_Char *name,    const XML_Char **atts);
    static void endElementHandler           (void *userData, const XML_Char *name);
    static void characterDataHandler        (void *userData, const XML_Char *s, int len);

    // Members
    XMLParserHandler *_handler;
    XML_Parser        _parser;
    std::string       _path;
    std::string       _errorText;
    int               _errorLineNumber;
    int               _errorColumnNumber;

    // Disable copy constructors
    XMLParser(const XMLParser &);
    XMLParser& operator=(const XMLParser &);
  };
}


#endif

